#ifndef KVPICKOP_H
#define KVPICKOP_H
#include <QObject>
#include <QMutex>
#include <QList>
#include <QPair>

class QThread;

// 找茬操作的接口类
class KvPickOp : public QObject
{
    Q_OBJECT

public:

    KvPickOp();
    ~KvPickOp();

    virtual void start(const QSet<QString>& workspace, bool includeSubDirs);

    virtual void stop(bool wait);

    // 还有多少文件在队列中等待计算
    int queued() const { return filesQueue_.size(); }

    bool pickNonHoles() const { return pickNonHoles_; }
    void setPickNonHoles(bool b) { pickNonHoles_ = b; }

protected:

    // 一个文件处理经过3个步骤，pick->read->calc

    // 返回true，才接续执行read步骤
    virtual bool doPick_(const QString& filePath) { return true; };

    // 返回指针非空，才接续执行calc步骤
    virtual void* doRead_(const QString& filePath) = 0;

    virtual void doCalc_(const QString& filePath, void* fileObj) = 0;

    // 用来释放doRead_返回的对象
    virtual void dropFileObject_(void* fileObj) = 0;

    void cleanFilesQueue_();

    // 发送结果信号的辅助函数，只对无分组op有效（主要为兼容反找茬模式）
    void tryEmitResult_(const QString& filePath, bool isHole);

signals:

    void started(); // 作业开始
    void finished(); // 作业结束或停止

    // 该信号发生的次数，等于待扫描的文件总数
    void filePicked(const QString& path, bool res);

    // 该信号发生的次数，小于等于待扫描的文件总数，因为有的文件挂起后并不触发读取操作
    // obj等于nullptr表示读取失败，obj有效才进入计算等待队列
    void fileRead(const QString& path, void* obj);

    // 该信号发生的次数，等于成功读取文件的总数
    void fileDone(const QString& path);

    void readout(); // 所有文件读取完成，读取线程功成身退

    void alldone(); // 所有操作全部完成，计算线程功成身退

    void resultFound(int group, const QString& path); // 匹配到一个新的结果

private:
    bool readDone_{ false }; // 所有文件读取完成的标记

    QList<QPair<QString, void*>> filesQueue_; // 文件队列，读取线程push，计算线程fetch
    int maxQueueSize_{ 1024 }; // 文件队列的最大尺寸

    QMutex mutex_; // 用于同步文件队列的读写操作

    QThread* readThread_{ nullptr };
    QThread* calcThread_{ nullptr };

    // 反找茬，只对无分组的op有效
    bool pickNonHoles_{ false };
};

#endif // KVPICKOP_H
